package com.code.wordhelper.utils;

import com.code.wordhelper.model.ImageData;
import com.sun.corba.se.impl.ior.OldJIDLObjectKeyTemplate;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.FileInputStream;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class CellTemplateUtils {
    private static Logger logger = LoggerFactory.getLogger(CellTemplateUtils.class);

    public static void replaceParagraphs(List<XWPFParagraph> paragraphs, Object value, String placeholderPrefix, String placeholderSuffix, String placeholder) throws Exception {
        for (int i = 0; i < paragraphs.size(); i++) {
            XWPFParagraph paragraph = paragraphs.get(i);
            if (!PatternUtils.match(paragraph.getText(), placeholder)) {
                continue;
            }
            replaceParagraph(paragraph, value, placeholderPrefix, placeholderSuffix, placeholder);
        }
    }

    public static void replaceParagraph(XWPFParagraph paragraph, Object value, String placeholderPrefix, String placeholderSuffix, String placeholder) throws Exception {
        List<XWPFRun> runList = paragraph.getRuns();
        Pattern pattern = Pattern.compile(placeholder);

        if (CollectionUtils.isEmpty(runList)) {
            return;
        }
        int prev = -1;
        int prevIdx = 0;
        int last = -1;
        int lastIdx = 0;
        for (int i = 0; i < runList.size(); i++) {
            if (!CollectionUtils.isEmpty(runList.get(i).getEmbeddedPictures())) {
                continue;
            }
            if (StringUtils.isEmpty(runList.get(i).text())) {
                continue;
            }
            String runText = runList.get(i).text();
            if (runText.contains(placeholderPrefix)) {
                //处理同一个段落出现多个${}
                if (prev == i) {
                    prevIdx = runText.indexOf(placeholderPrefix, prevIdx + 1);
                } else {
                    prevIdx = runText.indexOf(placeholderPrefix);
                }
                prev = i;
            }
            if (runText.contains(placeholderSuffix)) {
                //处理同一个段落出现多个${}
                if (last == i) {
                    lastIdx = runText.indexOf(placeholderSuffix, prevIdx + 1);
                } else {
                    lastIdx = runText.indexOf(placeholderSuffix);
                }
                last = i;
                if (prev == -1 || last == -1) {
                    continue;
                }
                if (prevIdx == -1 || lastIdx == -1) {
                    continue;
                }

                String placeholderKey = concatRun(runList, prev, last, prevIdx, lastIdx);
                if (StringUtils.isEmpty(placeholderKey) || !pattern.matcher(placeholderKey).find()) {
                    continue;
                }
                logger.info("placeholderKey:{}", placeholderKey);
                replaceTemplate(paragraph, runList, placeholderKey, prev, last, prevIdx, lastIdx, value, pattern);
            }
            //判断当前run是否存在多个替换
            if (runText.indexOf(placeholderPrefix, prevIdx + 1) != -1) {
                i--;
            }
        }
    }

    private static void replaceTemplate(XWPFParagraph paragraph, List<XWPFRun> runList, String placeholderKey, int prev, int last, int prevIdx, int lastIdx, Object value, Pattern pattern) throws Exception {
        String mapKey = PatternUtils.regex(placeholderKey, pattern, 1);
        if (value == null) {
            value = "";
        }

        logger.info("mapKey:{}, mapValue:{}", mapKey, value);
        replaceRunTemplate(paragraph, runList, prev, last, prevIdx, lastIdx, value);
    }

    /**
     * 拼接多个run之间的内容,组成key
     *
     * @param runList
     * @param start
     * @param end
     * @param prevIdx
     * @param lastIdx
     * @return
     */
    private static String concatRun(List<XWPFRun> runList, int start, int end, int prevIdx, int lastIdx) {
        if (start == end) {
            return runList.get(start).text().substring(prevIdx, lastIdx + 1);
        }
        StringBuffer stringBuffer = new StringBuffer();

        for (int i = start; i <= end; i++) {
            if (i == start) {
                stringBuffer.append(runList.get(i).text().substring(prevIdx));
            } else if (i == end) {
                stringBuffer.append(runList.get(i).text().substring(0, lastIdx + 1));
            } else {
                stringBuffer.append(runList.get(i).text());
            }
        }
        return stringBuffer.toString();
    }

    /**
     * 删除${}之间多余的内容
     *
     * @param runList
     * @param prev
     * @param last
     * @param prevIdx
     * @param lastIdx
     */
    private static void replaceRunTemplate(XWPFParagraph paragraph, List<XWPFRun> runList, int prev, int last, int prevIdx, int lastIdx, Object value) throws Exception {
        String prevRunText = runList.get(prev).text();
        String lastRunText = runList.get(last).text();

        logger.info("prev:{}-prevIdx:{}, last:{}-lastIdx:{}", prev, prevIdx, last, lastIdx);
        if (prev == last) {
            // 如果${}位于同一行，则删除key
            if (lastIdx == prevRunText.length() - 1) {
                if (value instanceof ImageData) {
                    runList.get(prev).setText(prevRunText.substring(0, prevIdx), 0);

                    ImageData imageData = (ImageData) value;
                    runList.get(prev).addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(), Units.toEMU(imageData.getWidth()), Units.toEMU(imageData.getHeight()));
                } else {
                    runList.get(prev).setText(prevRunText.substring(0, prevIdx) + value, 0);
                }
            } else {
                if (value instanceof ImageData) {
                    String textBefore = prevRunText.substring(0, prevIdx);
                    String textAfter = prevRunText.substring(lastIdx + 1);

                    runList.get(prev).setText(textBefore, 0);
                    ImageData imageData = (ImageData) value;
                    runList.get(prev).addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(), Units.toEMU(imageData.getWidth()), Units.toEMU(imageData.getHeight()));
                    runList.get(prev).setText(textAfter);
                } else {
                    prevRunText = prevRunText.substring(0, prevIdx) + value + prevRunText.substring(lastIdx + 1);
                    runList.get(prev).setText(prevRunText, 0);
                }
            }
        } else {
            // 如果${}不位于同一行，则删除多余的run
            if (value instanceof ImageData) {
                runList.get(prev).setText(prevRunText.substring(0, prevIdx), 0);

                ImageData imageData = (ImageData) value;
                runList.get(prev).addPicture(new FileInputStream(imageData.getUrl()), format(imageData.getExt()).nativeId, imageData.getFilename(), Units.toEMU(imageData.getWidth()), Units.toEMU(imageData.getHeight()));
            } else {
                runList.get(prev).setText(prevRunText.substring(0, prevIdx) + value, 0);
            }

            if (lastIdx == lastRunText.length() - 1) {
                runList.get(last).setText("", 0);
            } else {
                lastRunText = lastRunText.substring(lastIdx + 1);
                runList.get(last).setText(lastRunText, 0);
            }

            for (int i = prev + 1; i < last; i++) {
                runList.get(i).setText("", 0);
            }
        }
    }

    private static PictureData.PictureType format(String ext) {
        if ("JPEG".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.JPEG;
        } else if ("PNG".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.PNG;
        } else if ("SVG".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.SVG;
        } else if ("GIF".equalsIgnoreCase(ext)) {
            return PictureData.PictureType.GIF;
        }
        return PictureData.PictureType.JPEG;
    }
}
